<template>
  <view class="program-meta">
    <!-- 标题 -->
    <template v-if="scene === LearningViewScene.Detail">
      <view class="detail-title">
        <view class="title-main">
          <text class="title-text">{{ $t('Appliance.LearningProgram.Meta.Title.Text') }}</text>
          <image
            class="intro-icon"
            mode="aspectFit"
            :src="'/pages/appliance/static/ic_question_icon.png'"
            @click="emit('open-intro')"
          />
        </view>
        <view v-if="control.store.learningPhase === LearningPhase.Initial" class="title-aside">
          <TextButton size="small" :disabled="false" @click="emit('open-presetting')">{{
            $t('Appliance.LearningProgram.Meta.ToPresetting.Button.Text')
          }}</TextButton>
        </view>
      </view>
    </template>
    <template v-else-if="scene === LearningViewScene.Feedback">
      <view class="proposal-title">{{ proposalName }}</view>
    </template>

    <!-- Level -->
    <view class="levels">
      <view v-for="(option, index) in levelOptions" :key="index" class="level-item">
        <view class="level-header">
          <view class="level-title">
            <image class="level-icon" mode="aspectFit" :src="option.icon" />
            <text>{{ option.label }}</text>
          </view>
          <view v-if="option.value !== null" class="level-extra">
            <text>{{ option.value }}</text>
          </view>
        </view>

        <view class="level-percentage" :style="{ '--percent': `${option.percent}%` }" />
      </view>
    </view>

    <!-- 用量 -->
    <view class="meta-info">
      <view v-for="(meta, index) in metaInfo" :key="index" class="meta-item">
        <image class="meta-icon" mode="aspectFit" :src="meta.icon" />
        <text class="meta-value">{{ meta.value !== null ? meta.value : '--' }}</text>
      </view>
    </view>

    <!-- 声明 -->
    <view class="disclaimer">
      <text>{{ $t('Appliance.LearningProgram.Meta.Disclaimer.Text') }}</text>
    </view>
  </view>
</template>

<script setup lang="ts">
import { getProgramMetadata } from '@/api/appliance'
import {
  LearningProgramKey,
  LearningLevelKey,
  getMetaQueryKey,
  LearningDimension,
  type ProposalType,
  LearningPhase,
} from '@/controller/Dishwasher/Learning/constants'
import type { DishwasherController } from '@/controller/Dishwasher/definition'
import { useI18n } from 'vue-i18n'
import { LearningViewScene, useFullProposalMap } from '../constants'
import { getAllDimensionLevelKeys } from '@/controller/Dishwasher/Learning/constants'
import type { LearningLevelValue } from '@/controller/Dishwasher/Learning/constants'
import dayjs from 'dayjs'
import TextButton from '@/common/textButton.vue'
import { showLoading } from '@/utils/mpHelper'

const props = defineProps<{
  control: DishwasherController.Control
  proposalType: ProposalType | null
  isPerfectProposal?: boolean
  /**
   * 组件场景
   */
  scene: LearningViewScene
  // 预设置是否被禁用 (Detail场景使用)
  presettingDisabled?: boolean
  // 组件挂载时自动加载Metadata
  autoLoadMetadata?: boolean
}>()
const emit = defineEmits<{
  (e: 'open-intro'): void
  (e: 'open-presetting'): void
}>()

const i18n = useI18n()

/**
 * 页面数据来源
 */
const fullProposalMap = useFullProposalMap({
  isPerfectProposal: computed(() => props.isPerfectProposal),
})
const proposalName = computed(() => {
  if (!props.proposalType) return ''
  return fullProposalMap.value[props.proposalType] || ''
})

// Level 数据
type LevelValues = Record<LearningLevelKey, LearningLevelValue | null>
const levelValues = computed<LevelValues>(() => {
  let levelValues: LevelValues = {
    [LearningLevelKey.Cleaning]: null,
    [LearningLevelKey.Drying]: null,
    [LearningLevelKey.Duration]: null,
  }
  if (props.proposalType === null) return levelValues

  const levelKeys = getAllDimensionLevelKeys(props.proposalType)

  // 从Status中取三种Level的值
  levelValues = props.control.store._datasource.status.reduce((values, status) => {
    const keyInfo = levelKeys.find(({ key }) => key === status.key)
    if (keyInfo) {
      values[keyInfo.type] = status.value as LearningLevelValue
    }
    return values
  }, levelValues)

  return levelValues
})

// Meta 数据
type MetaData = {
  // 总耗时
  totalDuration: number | null
  // 用水量 (带单位)
  waterConsumption: string
  // 用电量 (带单位)
  energyConsumption: string
  // 洗涤温度 (带单位)
  washingTemperature: string
  // 百分比
  percentage: Record<LearningDimension, number>
}
const metaData = ref<MetaData | null>(null)
async function loadMetaData() {
  if (Object.values(levelValues.value).some((val) => val === null)) return

  const haId = props.control.store._datasource.haId
  const parameters = (Object.entries(levelValues.value) as [LearningLevelKey, LearningLevelValue | null][]).map(
    ([levelType, value]) => {
      return {
        key: getMetaQueryKey(levelType),
        value,
      }
    }
  )

  const res = await showLoading(() =>
    getProgramMetadata(haId, LearningProgramKey, {
      parameters,
      useDefaultSettings: true,
    })
  )
  const { metadata } = res.data.data

  // 根据接口返回 计算数据
  try {
    // 数值
    const totalDuration = safeCalculate(
      () => {
        return metadata.data['Runtime.Total']
      },
      { fallback: null }
    ) as number | null
    const waterConsumption = safeCalculate(
      () => {
        return metadata.data['Consumption.Water'] / 1000
      },
      { fallback: '', unit: i18n.t('Appliance.LearningProgram.Meta.Unit.Water.Text') }
    ) as string
    const energyConsumption = safeCalculate(
      () => {
        return metadata.data['Consumption.Energy'] / 1000
      },
      { fallback: '', unit: i18n.t('Appliance.LearningProgram.Meta.Unit.Energy.Text') }
    ) as string
    const washingTemperature = safeCalculate(
      () => {
        return metadata.data['Temperature.Washing.Max']
      },
      { fallback: '', unit: i18n.t('Appliance.LearningProgram.Meta.Unit.Temperature.Text') }
    ) as string

    // 百分比
    const cleaningPercentage = safeCalculate(() => metadata.data['Performance.LearningDishwasher.Cleaning'], {
      fallback: 0,
    }) as number
    const dryingPercentage = safeCalculate(() => metadata.data['Performance.LearningDishwasher.Drying'], {
      fallback: 0,
    }) as number
    const durationPercentage = safeCalculate(() => metadata.data['Performance.LearningDishwasher.Runtime'], {
      fallback: 0,
    }) as number

    metaData.value = {
      totalDuration,
      waterConsumption,
      energyConsumption,
      washingTemperature,
      percentage: {
        [LearningDimension.Cleaning]: cleaningPercentage,
        [LearningDimension.Drying]: dryingPercentage,
        [LearningDimension.Duration]: durationPercentage,
      },
    }
  } catch (e) {
    console.error(e)
  }
}
onBeforeMount(() => {
  props.autoLoadMetadata && loadMetaData()
})
// MetaData 已加载时 再刷新 否则不刷新(需要手动加载 或设置props.autoLoadMetadata)
watch(
  () => levelValues.value,
  () => metaData.value !== null && loadMetaData()
)

/**
 * 页面渲染数据
 */
type LevelOption = {
  icon: string
  label: string
  value: string | null
  percent: number
}
const levelOptions = computed<LevelOption[]>(() => {
  return [
    {
      icon: '/pages/appliance/static/learning/Cleaning.png',
      label: i18n.t('Appliance.LearningProgram.Meta.Cleaning.Text'),
      value: null,
      percent: metaData.value?.percentage[LearningDimension.Cleaning] || 0,
    },
    {
      icon: '/pages/appliance/static/learning/Drying.png',
      label: i18n.t('Appliance.LearningProgram.Meta.Drying.Text'),
      value: null,
      percent: metaData.value?.percentage[LearningDimension.Drying] || 0,
    },
    {
      icon: '/pages/appliance/static/learning/RunTime.png',
      label: i18n.t('Appliance.LearningProgram.Meta.Duration.Text'),
      value: metaData.value?.totalDuration ? getTimeText(metaData.value.totalDuration) : null,
      percent: metaData.value?.percentage[LearningDimension.Duration] || 0,
    },
  ]
})
function getTimeText(time: number): string {
  if (typeof time !== 'number') return ''

  const timeFormatted = dayjs().hour(0).minute(0).second(time).format('H:m')
  const [hour, minute] = timeFormatted.split(':')

  const hourText =
    hour !== '0' ? i18n.t('Appliance.LearningProgram.Meta.Duration.Hour.Text').replace('{hour}', hour) : ''
  const minText = i18n.t('Appliance.LearningProgram.Meta.Duration.Minute.Text').replace('{minute}', minute)
  return hourText + minText
}

type MetaInfoItem = {
  icon: string
  value: string | null
}
const metaInfo = computed<MetaInfoItem[]>(() => {
  return [
    {
      icon: '/pages/appliance/static/learning/Water.png',
      value: metaData.value?.waterConsumption || null,
    },
    {
      icon: '/pages/appliance/static/learning/Electricity.png',
      value: metaData.value?.energyConsumption || null,
    },
    {
      icon: '/pages/appliance/static/learning/Temperature.png',
      value: metaData.value?.washingTemperature || null,
    },
  ]
})

/**
 * 安全计算方法
 *
 *  - 出错时 返回options.fallback的值
 *  - 计算正确
 *     - 无计算单位时 返回number类型的计算结果值
 *     - 有计算单位时 返回string类型的拼接过计算单位的值
 */
type SafeCalculateOptions<TFallback> = {
  fallback?: TFallback // 计算失败时 返回的回退值
  unit?: string // 数据单位
}
function safeCalculate<TFallback>(
  calculateFn: () => number | unknown,
  options: SafeCalculateOptions<TFallback> = {}
): number | string | TFallback | undefined {
  try {
    const result = calculateFn()
    const isValidNumber = typeof result === 'number' && !isNaN(result)
    if (!isValidNumber) return options.fallback

    if (options.unit) {
      return result + options.unit
    }
    return result
  } catch (e) {
    console.error('Calculate error: ', e)
    return options.fallback
  }
}
defineExpose({
  loadMetaData,
  metaData,
})
</script>

<style scoped lang="less">
.program-meta {
  background-color: #f4f4f6;
  padding: 24rpx;
}
.detail-title {
  color: rgba(var(--dark-vector), 0.6);
  margin-bottom: 18rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  .title-main {
    display: flex;
    align-items: center;
  }
  .title-text {
    font-weight: 500;
    font-size: 28rpx;
    line-height: 40rpx;
  }
  .intro-icon {
    width: 28rpx;
    height: 28rpx;
    margin-left: 8rpx;
  }
}
.proposal-title {
  color: var(--dark-color);
  font-weight: 500;
  font-size: 32rpx;
  line-height: 44rpx;
  margin-bottom: 32rpx;
}

.levels,
.meta-info {
  color: rgba(var(--dark-vector), 0.8);
}

.levels {
  .level-item {
    margin-bottom: 48rpx;
  }
  .level-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
  }
  .level-title {
    font-weight: 500;
    font-size: 36rpx;
    line-height: 50rpx;
    display: flex;
    align-items: center;
  }
  .level-icon {
    width: 48rpx;
    height: 48rpx;
    margin-right: 8rpx;
  }
  .level-extra {
    font-weight: 500;
    font-size: 24rpx;
    line-height: 34rpx;
    color: rgba(var(--dark-vector), 0.8);
  }
  .level-percentage {
    width: 100%;
    height: 16rpx;
    margin-top: 16rpx;
    background-color: rgba(var(--dark-vector), 0.1);
    position: relative;
    overflow: hidden;
    &::before {
      display: block;
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: var(--percent);
      height: 100%;
      background-color: var(--primary-color);
      transition: width 0.5s ease-in-out;
    }
  }
}

.meta-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 48rpx;
  .meta-item {
    flex: 1;
    font-weight: 400;
    font-size: 28rpx;
    line-height: 40rpx;
    padding: 0 16rpx;
    color: rgba(var(--dark-vector), 0.8);
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    + .meta-item::before {
      display: block;
      content: '';
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      width: 2rpx;
      height: 40rpx;
      background-color: rgba(var(--dark-vector), 0.2);
    }
  }
  .meta-icon {
    width: 48rpx;
    height: 48rpx;
  }
}

.disclaimer {
  font-weight: 400;
  font-size: 20rpx;
  line-height: 28rpx;
  color: rgba(var(--dark-vector), 0.56);
}
</style>
